# '''
# "doc_scanner.py" 文件中的 DocScanner 类提供了文档扫描的核心功能，功能包括
#     - 加载图片
#     - 找到文档的角落
#     - 裁剪图片
#
# - 通过将文档扫描功能封装在一个独立的类中，我们可以将其作为一个模块，方便在其他项目中重用。
# - 这种模块化的设计使得代码更加模块化、可扩展和可测试。
# - 它可以独立于其他部分进行开发、测试和维护，而不会对其他组件产生影响。
# - 此外，将文档扫描功能单独放在一个文件中，使得代码结构更清晰、易于理解和维护。
# - 通过将不同的功能分割到不同的文件中，我们可以更好地组织代码，减少文件的复杂性，并促进团队合作开发。
# '''



import cv2 as cv
import numpy as np


class DocScanner:
    def __init__(self):
        pass

    def load_image(self, file_path):
        """加载图片并找到文档的四个角落。"""
        img = cv.imread(file_path, 1)
        img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
        _, binary_img = cv.threshold(img_gray, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)
        contours, _ = cv.findContours(binary_img, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)

        # 找到最大周长的四边形的四个顶点
        extreme_pnts = None
        for c in contours:
            perimeter = cv.arcLength(c, True)
            approx = cv.approxPolyDP(c, 0.01 * perimeter, True)
            if len(approx) == 4:
                extreme_pnts = approx

        corners = self.order_points(extreme_pnts.reshape(4, 2)).astype(np.int32)
        return img, corners

    def order_points(self, pts):
        """对给定的四个点进行排序，返回排序后的点。"""
        rect = np.zeros((4, 2), dtype="float32")
        s = pts.sum(axis=1)
        rect[0] = pts[np.argmin(s)]
        rect[2] = pts[np.argmax(s)]
        diff = np.diff(pts, axis=1)
        rect[1] = pts[np.argmin(diff)]
        rect[3] = pts[np.argmax(diff)]

        print(f"0:左上角:{rect[0]},因为x,y的坐标和是: np.min(s)={np.min(s)}")
        print(f"1:右上角:{rect[1]},因为x,y的坐标差是: np.min(diff)={np.min(diff)}")
        print(f"2:右下角:{rect[2]},因为x,y的坐标和是: np.max(s)={np.max(s)}")
        print(f"3:左下角:{rect[3]},因为x,y的坐标差是: np.max(diff)={np.max(diff)}")

        return rect

    def crop_image(self, img, corners):
        """根据四个角落裁剪图片。"""
        top_left_corner = corners[0]
        top_right_corner = corners[1]
        bottom_right_corner = corners[2]
        bottom_left_corner = corners[3]

        width, height = self.get_image_dimensions(
            (top_left_corner, top_right_corner, bottom_right_corner, bottom_left_corner))
        dst_points = np.array([[0, 0], [width - 1, 0], [width - 1, height - 1], [0, height - 1]], dtype='float32')

        pts1 = corners.astype(np.float32)
        pts2 = dst_points.astype(np.float32)
        M = cv.getPerspectiveTransform(pts1, pts2)
        dst = cv.warpPerspective(img, M, (width, height))
        return dst

    def get_image_dimensions(self, corners):
        """计算图片的宽度和高度。"""
        width1 = np.linalg.norm(corners[1] - corners[0])
        width2 = np.linalg.norm(corners[3] - corners[2])
        width = max(int(width1), int(width2))
        height1 = np.linalg.norm(corners[3] - corners[0])
        height2 = np.linalg.norm(corners[2] - corners[1])
        height = max(int(height1), int(height2))
        return width, height
